1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
use std::ptr::NonNull;
use std::rc::Rc;

use crate::co;
use crate::decl::*;
use crate::gui::{*, events::*, privs::*};

/// Exposes button control
/// [notifications](https://learn.microsoft.com/en-us/windows/win32/controls/bumper-button-control-reference-notifications)
/// for a [`RadioGroup`](crate::gui::RadioGroup).
///
/// These event methods are just proxies to the
/// [`WindowEvents`](crate::gui::events::WindowEvents) of the parent window, who
/// is the real responsible for the child event handling.
///
/// You cannot directly instantiate this object, it is created internally by the
/// control.
pub struct RadioGroupEvents {
	parent_ptr: NonNull<Base>,
	ctrl_ids: Vec<u16>,
}

impl RadioGroupEvents {
	#[must_use]
	pub(in crate::gui) fn new(
		parent: &impl AsRef<Base>,
		ctrl_ids: Vec<u16>,
	) -> Self
	{
		Self {
			parent_ptr: NonNull::from(parent.as_ref()),
			ctrl_ids,
		}
	}

	#[must_use]
	fn parent_user_events(&self) -> &WindowEvents {
		unsafe { self.parent_ptr.as_ref().on() }
	}

	/// [`BN_CLICKED`](https://learn.microsoft.com/en-us/windows/win32/controls/bn-clicked)
	/// command notification for all radio buttons in the group.
	///
	/// Sent when the user clicks a button.
	///
	/// # Examples
	///
	/// ```no_run
	/// use winsafe::{self as w, prelude::*, gui};
	///
	/// let wnd: gui::WindowMain; // initialized somewhere
	/// # let wnd = gui::WindowMain::new(gui::WindowMainOpts::default());
	/// let radios: gui::RadioGroup;
	/// # let radios = gui::RadioGroup::new(&wnd, &[]);
	///
	/// radios.on().bn_clicked({
	///     let radios = radios.clone();
	///     move || -> w::AnyResult<()> {
	///         println!("Selected {}",
	///             radios.checked().unwrap()
	///                 .hwnd().GetWindowText()?,
	///         );
	///         Ok(())
	///     }
	/// });
	/// ```
	pub fn bn_clicked<F>(&self, func: F)
		where F: Fn() -> AnyResult<()> + 'static,
	{
		let shared_func = Rc::new(func);

		for ctrl_id in self.ctrl_ids.iter() {
			self.parent_user_events().wm_command(*ctrl_id, co::BN::CLICKED, {
				let shared_func = shared_func.clone();
				move || {
					shared_func()?;
					Ok(WmRet::HandledOk)
				}
			});
		}
	}

	/// [`BN_DBLCLK`](https://learn.microsoft.com/en-us/windows/win32/controls/bn-dblclk)
	/// command notification for all radio buttons in the group.
	///
	/// Sent when the user double-clicks a button. This notification code is
	/// sent automatically for [`BS::USERBUTTON`](crate::co::BS::USERBUTTON),
	/// [`BS::RADIOBUTTON`](crate::co::BS::RADIOBUTTON), and
	/// [`BS::OWNERDRAW`](crate::co::BS::OWNERDRAW) buttons. Other button types
	/// send only if they have the [`BS::NOTIFY`](crate::co::BS::NOTIFY) style.
	pub fn bn_dbl_clk<F>(&self, func: F)
		where F: Fn() -> AnyResult<()> + 'static,
	{
		let shared_func = Rc::new(func);

		for ctrl_id in self.ctrl_ids.iter() {
			self.parent_user_events().wm_command(*ctrl_id, co::BN::DBLCLK, {
				let shared_func = shared_func.clone();
				move || {
					shared_func()?;
					Ok(WmRet::HandledOk)
				}
			});
		}
	}

	/// [`BN_KILLFOCUS`](https://learn.microsoft.com/en-us/windows/win32/controls/bn-killfocus)
	/// command notification for all radio buttons in the group.
	///
	/// Sent when a button loses the keyboard focus. The button must have the
	/// [`BS::NOTIFY`](crate::co::BS::NOTIFY) style to send this notification
	/// code.
	pub fn bn_kill_focus<F>(&self, func: F)
		where F: Fn() -> AnyResult<()> + 'static,
	{
		let shared_func = Rc::new(func);

		for ctrl_id in self.ctrl_ids.iter() {
			self.parent_user_events().wm_command(*ctrl_id, co::BN::KILLFOCUS, {
				let shared_func = shared_func.clone();
				move || {
					shared_func()?;
					Ok(WmRet::HandledOk)
				}
			});
		}
	}

	/// [`BN_SETFOCUS`](https://learn.microsoft.com/en-us/windows/win32/controls/bn-setfocus)
	/// command notification for all radio buttons in the group.
	///
	/// Sent when a button receives the keyboard focus. The button must have the
	/// [`BS::NOTIFY`](crate::co::BS::NOTIFY) style to send this notification
	/// code.
	pub fn bn_set_focus<F>(&self, func: F)
		where F: Fn() -> AnyResult<()> + 'static,
	{
		let shared_func = Rc::new(func);

		for ctrl_id in self.ctrl_ids.iter() {
			self.parent_user_events().wm_command(*ctrl_id, co::BN::SETFOCUS, {
				let shared_func = shared_func.clone();
				move || {
					shared_func()?;
					Ok(WmRet::HandledOk)
				}
			});
		}
	}
}